import networkx as nx
from shapely.geometry import LineString, MultiLineString, Polygon, MultiPolygon
from shapely.ops import unary_union, polygonize
from shapely import set_precision


class LoopStructure:
    def __init__(self, nodes, lines, geometry, area, perimeter, compactness):
        self.nodes = nodes
        self.lines = lines
        self.geometry = geometry
        self.area = area
        self.perimeter = perimeter
        self.compactness = compactness


def generate_water_supply_area(pipe_lines, buffer_radius=0.0003, precision=1e-8):
    """生成供水区域，优化环形区域处理"""
    if not pipe_lines:
        return None

    # 高精度坐标预处理
    pipe_lines = preprocess_pipe_lines_with_high_precision(pipe_lines, precision)

    # 识别环形结构和关键区域
    loop_structures = identify_loop_structures(pipe_lines)

    # 为不同类型的管线创建不同的缓冲区
    normal_buffer = create_normal_buffer(pipe_lines, loop_structures, buffer_radius)
    loop_buffer = create_optimized_loop_buffer(loop_structures, buffer_radius)

    # 合并缓冲区，处理重叠区域
    merged_buffer = merge_buffers_with_smart_strategy(normal_buffer, loop_buffer)

    # 后处理，清理可能的拓扑错误
    return post_process_buffer(merged_buffer)


def preprocess_pipe_lines_with_high_precision(pipe_lines, precision):
    """高精度坐标预处理"""
    # 使用Shapely的set_precision函数提高坐标精度
    processed_lines = []
    for line in pipe_lines:
        # 确保线串是有效的
        if not line.is_valid:
            line = line.buffer(0)  # 清理拓扑错误
        processed_lines.append(set_precision(line, precision))
    return processed_lines


def identify_loop_structures(pipe_lines):
    """识别并分析环形结构"""
    # 构建图
    G = nx.Graph()

    # 添加边
    for line in pipe_lines:
        start = tuple(line.coords[0])
        end = tuple(line.coords[-1])
        G.add_edge(start, end, geometry=line)

    # 识别所有简单环
    cycles = list(nx.simple_cycles(G))

    loop_structures = []
    for cycle in cycles:
        # 构建环的几何对象
        loop_lines = []
        for i in range(len(cycle)):
            start_node = cycle[i]
            end_node = cycle[(i + 1) % len(cycle)]

            # 查找对应的管线
            if G.has_edge(start_node, end_node):
                loop_lines.append(G[start_node][end_node]['geometry'])

        if loop_lines:
            # 构建环的几何
            loop_geometry = unary_union(loop_lines)
            if isinstance(loop_geometry, LineString):
                loop_geometry = loop_geometry.buffer(0)  # 确保是有效的几何

            # 计算环的几何特征
            area = loop_geometry.area
            perimeter = loop_geometry.length
            compactness = 4 * 3.14159 * area / (perimeter * perimeter) if perimeter > 0 else 0

            # 创建环结构对象
            loop_structure = LoopStructure(
                cycle, loop_lines, loop_geometry, area, perimeter, compactness)
            loop_structures.append(loop_structure)

    return loop_structures


def create_optimized_loop_buffer(loop_structures, buffer_radius):
    """创建优化的环形缓冲区"""
    loop_buffers = []

    for loop in loop_structures:
        # 对不同类型的环使用不同的缓冲区策略
        if loop.compactness > 0.8:
            # 对于紧凑的环（近似圆形）
            loop_buffers.append(create_compact_loop_buffer(loop, buffer_radius))
        elif loop.area / loop.perimeter < 0.01:
            # 对于狭窄的环
            loop_buffers.append(create_narrow_loop_buffer(loop, buffer_radius))
        else:
            # 一般情况
            loop_buffers.append(create_general_loop_buffer(loop, buffer_radius))

    if not loop_buffers:
        return None

    # 合并所有环形缓冲区
    return unary_union(loop_buffers)


def create_compact_loop_buffer(loop, buffer_radius):
    """创建紧凑环的缓冲区"""
    # 对于紧凑的环，使用平端帽和更精细的参数
    return loop.geometry.buffer(buffer_radius * 0.9, cap_style=1, join_style=1)


def create_narrow_loop_buffer(loop, buffer_radius):
    """创建狭窄环的缓冲区"""
    # 对于狭窄的环，使用特殊策略避免内部连接
    # 1. 先对环进行加厚
    thickened_loop = loop.geometry.buffer(buffer_radius * 0.3)

    # 2. 创建环的边界缓冲区
    boundary_buffer = loop.geometry.buffer(buffer_radius, cap_style=1, join_style=1)

    # 3. 从边界缓冲区中减去加厚的环，保留边界区域
    return boundary_buffer.difference(thickened_loop)


def create_general_loop_buffer(loop, buffer_radius):
    """创建一般环形结构的缓冲区"""
    # 对于一般环形结构，使用标准缓冲区策略
    # 采用平端帽(cap_style=2)避免端点处的圆形扩展
    # 使用斜接连接(join_style=1)处理尖锐角
    return loop.geometry.buffer(buffer_radius, cap_style=1, join_style=1)


def merge_buffers_with_smart_strategy(normal_buffer, loop_buffer):
    """智能合并缓冲区策略"""
    if normal_buffer is None:
        return loop_buffer

    if loop_buffer is None:
        return normal_buffer

    # 1. 计算重叠区域
    try:
        intersection = normal_buffer.intersection(loop_buffer)
    except Exception as e:
        print(f"计算缓冲区重叠区域失败: {e}")
        intersection = None

    # 2. 根据重叠情况选择合并策略
    if intersection and not intersection.is_empty:
        overlap_ratio = intersection.area / loop_buffer.area

        if overlap_ratio > 0.5:
            # 高重叠情况：使用谨慎的合并
            return cautious_merge(normal_buffer, loop_buffer, intersection)
        else:
            # 低重叠情况：直接合并
            try:
                return unary_union([normal_buffer, loop_buffer])
            except Exception as e:
                print(f"直接合并缓冲区失败: {e}")
                return normal_buffer

    # 没有重叠，直接合并
    try:
        return unary_union([normal_buffer, loop_buffer])
    except Exception as e:
        print(f"合并缓冲区失败: {e}")
        return normal_buffer


def cautious_merge(normal_buffer, loop_buffer, intersection):
    """谨慎合并缓冲区，避免错误连接"""
    # 1. 对重叠区域进行收缩
    shrunk_intersection = intersection.buffer(-0.1)

    # 2. 创建连接区域
    if not shrunk_intersection.is_empty:
        connector = shrunk_intersection.buffer(0.05)
    else:
        connector = intersection

    # 3. 合并三个部分
    try:
        return unary_union([normal_buffer, loop_buffer, connector])
    except Exception as e:
        print(f"谨慎合并缓冲区失败: {e}")
        return unary_union([normal_buffer, loop_buffer])


def create_normal_buffer(pipe_lines, loop_structures, buffer_radius):
    """创建普通管线的缓冲区"""
    # 从原始管线中排除环形管线
    loop_nodes = set()
    for loop in loop_structures:
        loop_nodes.update(loop.nodes)

    normal_lines = []
    for line in pipe_lines:
        start = tuple(line.coords[0])
        end = tuple(line.coords[-1])
        if start not in loop_nodes and end not in loop_nodes:
            normal_lines.append(line)

    if not normal_lines:
        return None

    # 创建普通管线的缓冲区
    normal_geoms = [line.buffer(buffer_radius, cap_style=1, join_style=1) for line in normal_lines]
    return unary_union(normal_geoms)


def post_process_buffer(buffer):
    """后处理缓冲区，清理拓扑错误"""
    if buffer is None:
        return None

    try:
        # 清理可能的拓扑错误
        return buffer.buffer(0)
    except Exception as e:
        print(f"后处理缓冲区失败: {e}")
        return buffer

